package com.da.javalog.template.core;

import java.util.HashMap;
import java.util.Map;

import com.da.javalog.template.annotation.BaseTemplate;
import com.da.javalog.template.annotation.ExtTemplate;
import com.da.javalog.template.annotation.TemplateInterface;
import com.da.javalog.utils.AssertUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * @author chenlida
 * @date 2020/9/13 23:09
 * @description
 */
@Slf4j
public class TemplateManager {
    private static final String DEFAULT_MERCHANT_CODE = "default_merchant_code";

    private static final Map<String, Object> templateMap = new HashMap<>();

    /**
     * 按商家编码找模板类，如果商家没有配置额外的处理类就找基类
     *
     * @param merchantCode 商家编码
     * @param cls          基类的class，也就是BaseTemplate注解的class
     * @param <T>
     * @return
     */
    public static <T> T getTemplate(String merchantCode, Class<T> cls) {
        AssertUtils.notNullAndMsg(merchantCode, "merchantCode");
        TemplateInterface templateInterface = cls.getAnnotation(TemplateInterface.class);
        AssertUtils.notNullAndMsg(templateInterface, "templateInterface");
        String templateId = getTemplateId(cls);
        String key = merchantCode + "_" + templateId;
        Object object = templateMap.get(key);
        if (object == null) {
            key = DEFAULT_MERCHANT_CODE + "_" + templateId;
            object = templateMap.get(key);
        }
        return (T)object;
    }

    public static void process(Object bean, String beanName) {
        Class targetClass = getTargetClass(bean);
        log.warn("TemplateManager.process bean={}, beanName={}, targetClass={}", bean.getClass().getName(), beanName,
            targetClass);
        BaseTemplate baseTemplate = (BaseTemplate)targetClass.getAnnotation(BaseTemplate.class);
        if (baseTemplate != null) {
            log.warn("BaseTemplate bean : {}", beanName);
            //管理默认实现
            String templateId = getTemplateId(targetClass);
            AssertUtils.notNullAndMsg(templateId, "templateId");
            String merchantCodeTemplateKey = DEFAULT_MERCHANT_CODE + "_" + templateId;
            put(merchantCodeTemplateKey, bean);

        }
        ExtTemplate extTemplate = (ExtTemplate)targetClass.getAnnotation(ExtTemplate.class);
        if (extTemplate != null) {
            log.warn("ExtTemplate bean : {}, merchantCodeList:{}", beanName, extTemplate.merchantCodeList());
            Class baseCls = getBaseTemplateClass(targetClass);
            AssertUtils.notNull(baseCls, "@ExtTemplate一定要继承@BaseTemplate的类");
            String templateId = getTemplateId(baseCls);
            AssertUtils.notNullAndMsg(templateId, "templateId");
            if (AssertUtils.isNotEmpty(extTemplate.merchantCodeList())) {
                for (String merchantCode : extTemplate.merchantCodeList()) {
                    String key = merchantCode + "_" + templateId;
                    put(key, bean);
                }
            }
        }
    }

    /**
     * 获取模板子类的父类
     *
     * @param subClass
     * @return
     */
    private static Class getBaseTemplateClass(Class subClass) {
        Class it = subClass;
        /**
         * 最多找5层，防止父类不存在而循环导致性能下降
         */
        for (int i = 0; i < 5; i++) {
            if (it.getAnnotation(BaseTemplate.class) != null) {
                return it;
            } else {
                it = it.getSuperclass();
                if (it == null) {
                    return null;
                }
            }
        }
        return null;
    }

    private static String getTemplateId(Class cls) {
        if (cls.isInterface()) {
            return cls.getSimpleName();
        } else {
            Class[] interfaces = cls.getInterfaces();
            for (Class i : interfaces) {
                if (i.getAnnotation(TemplateInterface.class) != null) {
                    return i.getSimpleName();
                }
            }
        }
        return null;
    }

    private static void put(String key, Object bean) {
        log.warn("key={},bean={}", key, bean.getClass().getName());
        templateMap.put(key, bean);
    }

    private static Class getTargetClass(Object bean) {
        Class clz = bean.getClass();
        String fullName = clz.getName();
        if (fullName.contains("EnhancerBySpringCGLIB") || fullName.contains("$$")) {
            fullName = fullName.substring(0, fullName.indexOf("$$"));
            try {
                clz = Class.forName(fullName);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        return clz;
    }
}
